/* Copyright (C) 2004 - 2006  db4objects Inc.  http://www.db4o.com

This file is part of the db4o open source object database.

db4o is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation and as clarified by db4objects' GPL 
interpretation policy, available at
http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
Suite 350, San Mateo, CA 94403, USA.

db4o is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */
namespace Db4objects.Db4o.Internal.Fileheader
{
	/// <exclude></exclude>
	public class FileHeader1 : Db4objects.Db4o.Internal.Fileheader.FileHeader
	{
		private static readonly byte[] SIGNATURE = { (byte)'d', (byte)'b', (byte)'4', (byte
			)'o' };

		private static byte VERSION = 1;

		private static readonly int HEADER_LOCK_OFFSET = SIGNATURE.Length + 1;

		private static readonly int OPEN_TIME_OFFSET = HEADER_LOCK_OFFSET + Db4objects.Db4o.Internal.Const4
			.INT_LENGTH;

		private static readonly int ACCESS_TIME_OFFSET = OPEN_TIME_OFFSET + Db4objects.Db4o.Internal.Const4
			.LONG_LENGTH;

		private static readonly int TRANSACTION_POINTER_OFFSET = ACCESS_TIME_OFFSET + Db4objects.Db4o.Internal.Const4
			.LONG_LENGTH;

		internal static readonly int LENGTH = TRANSACTION_POINTER_OFFSET + (Db4objects.Db4o.Internal.Const4
			.INT_LENGTH * 6);

		private Db4objects.Db4o.Internal.Fileheader.TimerFileLock _timerFileLock;

		private Db4objects.Db4o.Internal.Transaction _interruptedTransaction;

		private Db4objects.Db4o.Internal.Fileheader.FileHeaderVariablePart1 _variablePart;

		public override void Close()
		{
			_timerFileLock.Close();
		}

		public override void InitNew(Db4objects.Db4o.Internal.LocalObjectContainer file)
		{
			CommonTasksForNewAndRead(file);
			_variablePart = new Db4objects.Db4o.Internal.Fileheader.FileHeaderVariablePart1(0
				, file.SystemData());
			WriteVariablePart(file, 0);
		}

		protected override Db4objects.Db4o.Internal.Fileheader.FileHeader NewOnSignatureMatch
			(Db4objects.Db4o.Internal.LocalObjectContainer file, Db4objects.Db4o.Internal.Buffer
			 reader)
		{
			if (SignatureMatches(reader, SIGNATURE, VERSION))
			{
				return new Db4objects.Db4o.Internal.Fileheader.FileHeader1();
			}
			return null;
		}

		private void NewTimerFileLock(Db4objects.Db4o.Internal.LocalObjectContainer file)
		{
			_timerFileLock = Db4objects.Db4o.Internal.Fileheader.TimerFileLock.ForFile(file);
			_timerFileLock.SetAddresses(0, OPEN_TIME_OFFSET, ACCESS_TIME_OFFSET);
		}

		public override Db4objects.Db4o.Internal.Transaction InterruptedTransaction()
		{
			return _interruptedTransaction;
		}

		public override int Length()
		{
			return LENGTH;
		}

		protected override void ReadFixedPart(Db4objects.Db4o.Internal.LocalObjectContainer
			 file, Db4objects.Db4o.Internal.Buffer reader)
		{
			CommonTasksForNewAndRead(file);
			CheckThreadFileLock(file, reader);
			reader.Seek(TRANSACTION_POINTER_OFFSET);
			_interruptedTransaction = Db4objects.Db4o.Internal.Transaction.ReadInterruptedTransaction
				(file, reader);
			file.BlockSizeReadFromFile(reader.ReadInt());
			ReadClassCollectionAndFreeSpace(file, reader);
			_variablePart = new Db4objects.Db4o.Internal.Fileheader.FileHeaderVariablePart1(reader
				.ReadInt(), file.SystemData());
		}

		private void CheckThreadFileLock(Db4objects.Db4o.Internal.LocalObjectContainer container
			, Db4objects.Db4o.Internal.Buffer reader)
		{
			reader.Seek(ACCESS_TIME_OFFSET);
			long lastAccessTime = reader.ReadLong();
			if (Db4objects.Db4o.Internal.Fileheader.FileHeader.LockedByOtherSession(container
				, lastAccessTime))
			{
				_timerFileLock.CheckIfOtherSessionAlive(container, 0, ACCESS_TIME_OFFSET, lastAccessTime
					);
			}
		}

		private void CommonTasksForNewAndRead(Db4objects.Db4o.Internal.LocalObjectContainer
			 file)
		{
			NewTimerFileLock(file);
			file.i_handlers.OldEncryptionOff();
		}

		public override void ReadVariablePart(Db4objects.Db4o.Internal.LocalObjectContainer
			 file)
		{
			_variablePart.Read(file.GetSystemTransaction());
		}

		public override void WriteFixedPart(Db4objects.Db4o.Internal.LocalObjectContainer
			 file, bool startFileLockingThread, bool shuttingDown, Db4objects.Db4o.Internal.StatefulBuffer
			 writer, int blockSize, int freespaceID)
		{
			writer.Append(SIGNATURE);
			writer.Append(VERSION);
			writer.WriteInt((int)TimeToWrite(_timerFileLock.OpenTime(), shuttingDown));
			writer.WriteLong(TimeToWrite(_timerFileLock.OpenTime(), shuttingDown));
			writer.WriteLong(TimeToWrite(Sharpen.Runtime.CurrentTimeMillis(), shuttingDown));
			writer.WriteInt(0);
			writer.WriteInt(0);
			writer.WriteInt(blockSize);
			writer.WriteInt(file.SystemData().ClassCollectionID());
			writer.WriteInt(freespaceID);
			writer.WriteInt(_variablePart.GetID());
			writer.NoXByteCheck();
			writer.Write();
			file.SyncFiles();
			if (startFileLockingThread)
			{
				try
				{
					_timerFileLock.Start();
				}
				catch (System.IO.IOException)
				{
				}
			}
		}

		public override void WriteTransactionPointer(Db4objects.Db4o.Internal.Transaction
			 systemTransaction, int transactionAddress)
		{
			WriteTransactionPointer(systemTransaction, transactionAddress, 0, TRANSACTION_POINTER_OFFSET
				);
		}

		public override void WriteVariablePart(Db4objects.Db4o.Internal.LocalObjectContainer
			 file, int part)
		{
			_variablePart.SetStateDirty();
			_variablePart.Write(file.GetSystemTransaction());
		}
	}
}
